package proyecto.testcasetool.presentation.details.scenario;

import java.util.Iterator;

import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.databinding.EMFUpdateValueStrategy;
import org.eclipse.emf.databinding.FeaturePath;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
import org.eclipse.emf.databinding.edit.EMFEditProperties;
import org.eclipse.emf.databinding.edit.IEMFEditValueProperty;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.IFormPart;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;

import proyecto.testcasetool.AlternativeFlow;
import proyecto.testcasetool.BasicFlow;
import proyecto.testcasetool.Step;
import proyecto.testcasetool.TestcasetoolPackage;
import proyecto.testcasetool.UseCase;


public class AlternativeFlowDetailsPage extends AbstractScenarioDetailsPage {

	private Text txtCondition;
	private Text txtBranchStep;
	private Text txtJoinStep;
	private Text txtPostCondition;
	
	
	public AlternativeFlowDetailsPage(FormToolkit toolkit, EditingDomain editingDomain,
			AdapterFactory adapterFactory) {
		super(toolkit, editingDomain, adapterFactory);
	}
	
	
	@Override
	protected void createDetailsSection(Composite parent) {
		super.createDetailsSection(parent);
		

		Control[] controls = parent.getChildren();
		Section section = (Section) controls[0];
		Composite client = (Composite) section.getClient();
		
		Label lblPostCondition = toolkit.createLabel(client, "Post-Condition", SWT.NONE);
		txtPostCondition = toolkit.createText(client, "", SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
		
		GridData gd_txtPostCondition = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
		gd_txtPostCondition.heightHint = 80;
		gd_txtPostCondition.verticalIndent = 10;
		gd_txtPostCondition.widthHint = 0;
		txtPostCondition.setLayoutData(gd_txtPostCondition);
		
		Label lblBranchStep = toolkit.createLabel(client, "Branch step", SWT.NONE);
		GridData gdLabelAlternative = new GridData();
		gdLabelAlternative.verticalIndent = 10;
		lblBranchStep.setLayoutData(gdLabelAlternative);
		
		txtBranchStep = toolkit.createText(client, "", SWT.NONE);
		GridData gd_txtStepId = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
		gd_txtStepId.verticalIndent = 10;
		gd_txtStepId.widthHint = 200;
		txtBranchStep.setLayoutData(gd_txtStepId);
		
		
		Label lblCondition = toolkit.createLabel(client, "Condition", SWT.NONE);
		GridData gdLabelCondition = new GridData();
		gdLabelCondition.verticalIndent = 10;
		lblCondition.setLayoutData(gdLabelCondition);
		
		txtCondition = toolkit.createText(client, "", SWT.NONE);
		GridData gd_txtCondition = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
		gd_txtCondition.verticalIndent = 10;
		gd_txtCondition.widthHint = 200;
		txtCondition.setLayoutData(gd_txtCondition);
		
		
		Label lblJoinStep = toolkit.createLabel(client, "Join step", SWT.NONE);
		GridData gdlblJoinStep = new GridData();
		gdlblJoinStep.verticalIndent = 10;
		lblJoinStep.setLayoutData(gdlblJoinStep);
		
		txtJoinStep = toolkit.createText(client, "", SWT.NONE);
		GridData gd_txtJoinStep = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
		gd_txtJoinStep.verticalIndent = 10;
		gd_txtJoinStep.widthHint = 200;
		txtJoinStep.setLayoutData(gd_txtJoinStep);
		
	}
	
	
	public void selectionChanged(IFormPart part, ISelection selection) {
		// controlar que sea la part que esto esperando!!!!
		if (!(selection instanceof IStructuredSelection)) {
			return;
		}
		EObject newEObject = getEObjectFromSelection(selection);
		if (newEObject != null && newEObject != eObject) {
			eObject = newEObject;
			if (eObject != null) {
				
				doBinding();
				
				observeBranchStep();
				
				observeJoinStep();
				
				IObservableValue obsCondFeature = EMFEditObservables
						.observeValue(editingDomain, eObject,
								TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__CONDITION);

				
				bindingContext.bindValue(SWTObservables.observeText(
						txtCondition, SWT.FocusOut), obsCondFeature);
				
				IObservableValue obsPostCondition = EMFEditObservables
						.observeValue(editingDomain, eObject,
								TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__POST_CONDITION
								);

				
				bindingContext.bindValue(SWTObservables.observeText(
						txtPostCondition, SWT.FocusOut), obsPostCondition);
				
				obsManager.addObservable(obsCondFeature);
				obsManager.addObservable(obsPostCondition);
				
				
			}
		}
	}


	private void observeBranchStep() {
		IEMFEditValueProperty brachStepProp = EMFEditProperties.value(
		  editingDomain,
		  FeaturePath.fromList(
				  TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__BRANCH_STEP,
				    TestcasetoolPackage.Literals.STEP__ID
		  )
		);
		IObservableValue obsbranchStep = brachStepProp.observe(eObject);
		
		ISWTObservableValue txtBranchStepObs = SWTObservables.observeText(
				txtBranchStep, SWT.FocusOut);
		
		bindingContext.bindValue(txtBranchStepObs, obsbranchStep,
				new EMFUpdateValueStrategy(EMFUpdateValueStrategy.POLICY_NEVER), new EMFUpdateValueStrategy(EMFUpdateValueStrategy.POLICY_UPDATE));

		txtBranchStepObs
		.addValueChangeListener(new IValueChangeListener() {

			@Override
			public void handleValueChange(ValueChangeEvent event) {
				
				String value = (String) event
						.getObservableValue().getValue();
				
				AlternativeFlow aflow = (AlternativeFlow) eObject;
				UseCase uc = (UseCase)aflow.eContainer();
				BasicFlow bf = uc.getBasicScenario();
				
				boolean encontre = false;
				Step stepAux = null;
				Iterator<Step> i = bf.getStep().iterator();
				while (!encontre && i.hasNext()){
					stepAux = i.next();
					if (stepAux.getId().equals(value)){
						encontre = true;
					}
				}
				
				if (!encontre){
					EList<AlternativeFlow> e = uc.getAlternativeFlow();
					for (AlternativeFlow alternativeFlow : e) {
						if (alternativeFlow != aflow){
							stepAux = null;
							i = alternativeFlow.getStep().iterator();
							while (!encontre && i.hasNext()){
								stepAux = i.next();
								if (stepAux.getId().equals(value)){
									encontre = true;
								}
							}
						}
					}
				}
				
				if (encontre){
					Command cmd = SetCommand
							.create(editingDomain,
									eObject,
									TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__BRANCH_STEP,
									stepAux);
					if (cmd.canExecute()){
						editingDomain.getCommandStack().execute(cmd);
					}
				}
				else{
					Command cmd = SetCommand
							.create(editingDomain,
									eObject,
									TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__BRANCH_STEP,
									SetCommand.UNSET_VALUE);
					if (cmd.canExecute()){
						editingDomain.getCommandStack().execute(cmd);
					}
				}
				
			}
		});
		
		obsManager.addObservable(obsbranchStep);
	}
	
	
	private void observeJoinStep() {
		IEMFEditValueProperty joinStepProp = EMFEditProperties.value(
		  editingDomain,
		  FeaturePath.fromList(
				  TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__JOIN_STEP,
				    TestcasetoolPackage.Literals.STEP__ID
		  )
		);
		IObservableValue obsjoinStep = joinStepProp.observe(eObject);
		
		ISWTObservableValue txtJoinStepObs = SWTObservables.observeText(
				txtJoinStep, SWT.FocusOut);
		
		bindingContext.bindValue(txtJoinStepObs, obsjoinStep,
				new EMFUpdateValueStrategy(EMFUpdateValueStrategy.POLICY_NEVER), new EMFUpdateValueStrategy(EMFUpdateValueStrategy.POLICY_UPDATE));

		txtJoinStepObs
		.addValueChangeListener(new IValueChangeListener() {

			@Override
			public void handleValueChange(ValueChangeEvent event) {
				
				String value = (String) event
						.getObservableValue().getValue();
				
				AlternativeFlow aflow = (AlternativeFlow) eObject;
				UseCase uc = (UseCase)aflow.eContainer();
				BasicFlow bf = uc.getBasicScenario();
				
				boolean encontre = false;
				Step stepAux = null;
				Iterator<Step> i = bf.getStep().iterator();
				while (!encontre && i.hasNext()){
					stepAux = i.next();
					if (stepAux.getId().equals(value)){
						encontre = true;
					}
				}
				
				if (encontre){
					Command cmd = SetCommand
							.create(editingDomain,
									eObject,
									TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__JOIN_STEP,
									stepAux);
					if (cmd.canExecute()){
						editingDomain.getCommandStack().execute(cmd);
					}
				}
				else{
					Command cmd = SetCommand
							.create(editingDomain,
									eObject,
									TestcasetoolPackage.Literals.ALTERNATIVE_FLOW__JOIN_STEP,
									SetCommand.UNSET_VALUE);
					if (cmd.canExecute()){
						editingDomain.getCommandStack().execute(cmd);
					}
				}
				
			}
		});
		
		obsManager.addObservable(obsjoinStep);
	}
	
	@Override
	public void dispose() {
		super.dispose();
	}



}
